package com.enlorenz.common.excel.input;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import com.enlorenz.common.util.FileUtils;
import com.enlorenz.common.util.FileUtils.IFileLineHook;
import com.enlorenz.common.util.StreamUtils;

/**
 * Excel数据解析
 * @author Karma
 */
public class ExcelDataImporter implements IDataImporter{
	public static final String FILE_TYPE_CSV="csv";
	public static final String FILE_TYPE_XLS="xls";
	public static final String FILE_TYPE_XLSX="xlsx";
	
	private String encoding="gbk";
	
	//路径类型
	public static final int IMPORT_TYPE_PATH=0;
	//输入流类型
	public static final int IMPORT_TYPE_IS=1;
	//class类型
	public static final int IMPORT_TYPE_CLASS=2;
	
	//输入流
	private InputStream is;
	//文件名
	private String fileName;
	//创建类型
	private int type;
	//类
	private Class<?> claxx;
	//文件路径
	private String path;
	
	/**
	 * 通过文件路径创建
	 * @param path 路径
	 */
	public ExcelDataImporter(String path){
		File file=new File(path);
		this.fileName=file.getName();
		this.path=path;
		type=IMPORT_TYPE_PATH;
	}
	
	/**
	 * 通过文件名和输入流创建
	 * @param fileName 文件名
	 * @param is 输入流
	 */
	public ExcelDataImporter(String fileName,InputStream is){
		this.fileName=fileName;
		this.is=is;
		type=IMPORT_TYPE_IS;
	}
	
	/**
	 * 通过类和文件名创建
	 * @param claxx 类
	 * @param fileName 文件名
	 */
	public ExcelDataImporter(Class<?> claxx,String fileName){
		this.fileName=fileName;
		this.claxx=claxx;
		type=IMPORT_TYPE_CLASS;
	}
	
	@Override
	public void parse(final IDataInputIterator iterator) {
		
		InputStream is=null;
		try{
			//创建输入流
			if(type == IMPORT_TYPE_PATH){
				is=new FileInputStream(path);
			}else if(type == IMPORT_TYPE_IS){
				is=this.is;
			}else if(type == IMPORT_TYPE_CLASS){
				is=claxx.getResourceAsStream(fileName);
			}
			
			String fileName=this.fileName.toLowerCase();
			//普通CSV文件
			if(fileName.endsWith(FILE_TYPE_CSV)){
				readCsv(is,iterator);
			//EXCEL　XLS文件
			}else if(fileName.endsWith(FILE_TYPE_XLS)){
				readXls(is,iterator);
			//EXCEL XLSX文件
			}else if(fileName.endsWith(FILE_TYPE_XLSX)){
				readXlsx(is, iterator);
			}
		}catch (Exception e) {
			throw new RuntimeException(e);
		}finally{
			StreamUtils.closeStream(is);
		}
	}
	

	private int rowIndex=0;
	/**
	 * 读取CSV
	 */
	private void readCsv(InputStream is,final IDataInputIterator iterator) {
		rowIndex=0;
		iterator.sheet(0, "default");
		FileUtils.readFileByLine(is, new IFileLineHook() {
			@Override
			public void hook(String lineStr) {
				String [] arr=lineStr.split(",");
				iterator.row(rowIndex,Arrays.asList(arr));
				rowIndex++;
			}
		},getEncoding());
	}
	
	/**
	 * 读取XLS
	 */
	private void readXls(InputStream is,final IDataInputIterator iterator){
		try{
			HSSFWorkbook hssfWorkbook = new HSSFWorkbook(is);
			// 循环工作表Sheet
			for (int numSheet = 0; numSheet < hssfWorkbook.getNumberOfSheets(); numSheet++) {
				HSSFSheet hssfSheet = hssfWorkbook.getSheetAt(numSheet);
				if (hssfSheet == null) {
					continue;
				}
				
				iterator.sheet(numSheet, hssfSheet.getSheetName());
				
				// 循环行Row
				for (int rowNum = 0; rowNum <= hssfSheet.getLastRowNum(); rowNum++) {
					HSSFRow hssfRow = hssfSheet.getRow(rowNum);
					if (hssfRow == null) {
						continue;
					}
					
					List<String> rows=new ArrayList<String>();
					
					// 循环列Cell
					for (int cellNum = 0; cellNum <= hssfRow.getLastCellNum(); cellNum++) {
						HSSFCell hssfCell = hssfRow.getCell(cellNum);
						if (hssfCell == null) {
							rows.add("");
							continue;
						}
						
						String value=getValue(hssfCell);
						if(null!=value){
							value=value.trim();
						}
						rows.add(value);
					}
					
					iterator.row(rowNum,rows);
				}
			}
		}catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 获取excel单元格的值
	 * @param hssfCell
	 * @return
	 */
	protected String getValue(HSSFCell hssfCell) {
		if (hssfCell.getCellType() == HSSFCell.CELL_TYPE_BOOLEAN) {
			return String.valueOf(hssfCell.getBooleanCellValue());
		} else if (hssfCell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC){ 
			String s=String.valueOf(hssfCell.getNumericCellValue());
			if(-1!=s.indexOf("E")){
				int cellValue_int = (int)hssfCell.getNumericCellValue();
				String cellValue=String.valueOf(cellValue_int);
				return cellValue;
			}else{
				return s;
			}
		} else {
			return hssfCell.getStringCellValue();
		}
	}
	
	/**
	 * 读取XLSX
	 */
	private void readXlsx(InputStream is,final IDataInputIterator iterator){
		try{
			XSSFWorkbook xssfWorkbook = new XSSFWorkbook(is);
			// 循环工作表Sheet
			for (int numSheet = 0; numSheet < xssfWorkbook.getNumberOfSheets(); numSheet++) {
				XSSFSheet xssfSheet = xssfWorkbook.getSheetAt(numSheet);
				if (xssfSheet == null) {
					continue;
				}
				iterator.sheet(numSheet, xssfSheet.getSheetName());
				// 循环行Row
				for (int rowNum = 0; rowNum <= xssfSheet.getLastRowNum(); rowNum++) {
					XSSFRow xssfRow = xssfSheet.getRow(rowNum);
					if (xssfRow == null) {
						continue;
					}
					
					List<String> rows=new ArrayList<String>();
					// 循环列Cell
					for (int cellNum = 0; cellNum <= xssfRow.getLastCellNum(); cellNum++) {
						XSSFCell xssfCell = xssfRow.getCell(cellNum);
						if (xssfCell == null) {
							continue;
						}
						String value=getValue(xssfCell);
						if(null!=value){
							value=value.trim();
						}
						rows.add(value);
					}
					iterator.row(rowNum,rows);
				}
			}
		}catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	private String getValue(XSSFCell xssfCell) {
		if (xssfCell.getCellType() == XSSFCell.CELL_TYPE_BOOLEAN) {
			return String.valueOf(xssfCell.getBooleanCellValue());
		} else if (xssfCell.getCellType() == XSSFCell.CELL_TYPE_NUMERIC) {
			return String.valueOf(xssfCell.getNumericCellValue());
		} else {
			return xssfCell.getStringCellValue();
		}
	}
	
	private List<ExcelSheetData> list;
	private ExcelSheetData curSheet;
	@Override
	public List<ExcelSheetData> parse() {
		list=new ArrayList<ExcelSheetData>();
		
		IDataInputIterator iterator=
		new IDataInputIterator() {
			@Override
			public void sheet(int sheetNum, String sheetName) {
				curSheet=new ExcelSheetData();
				curSheet.setSheetName(sheetName);
				curSheet.setSheetNum(sheetNum);
				list.add(curSheet);
			}

			@Override
			public void row(int rowNum, List<String> colLost) {
				curSheet.getRowList().add(colLost);
			}
		};
		parse(iterator);
		
		return list;
	}

	public String getEncoding() {
		return encoding;
	}

	public void setEncoding(String encoding) {
		this.encoding = encoding;
	}
	
}
